﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using bfs.sms.sdmx.util.Variable;
using SdmxMl.Structure;
using SdmxMl.Common;

namespace bfs.sms.sdmx.util.SAS
{
    public class FormatCatalog
    {

        private string langCd;
        private StringBuilder sb;

        /// <summary> SAS Format generation </summary>
        /// <param name="varSheets">Collection of sheets holding variables to treat</param>
        /// <param name="lang">language code to use</param>
        public void GenerateCodeFormat(List<VariableSheet> varSheets, string lang)
        {
            langCd = lang;
            sb = new StringBuilder();
            foreach (VariableSheet vs in varSheets)
            {
                foreach (Variable.Variable var in vs.VarList)
                    FillCodelistFormat(sb, vs, var);
            }
        }

        public void Save(string path)
        {
            if (sb != null && sb.Length > 0)
            {
                using (StreamWriter sw = new StreamWriter(path, false, Encoding.Default))
                {
                    sw.Write(sb.ToString());
                }
            }
        }

        /// <summary> Provides a comment before Format instructions </summary>
        /// <param name="sb">the text builder to use</param>
        /// <param name="vs">the current sheet informations</param>
        /// <param name="var"></param>
        private void CommentFormat(StringBuilder sb, VariableSheet vs, Variable.Variable var)
        {
            sb.Append("/*").Append(Environment.NewLine);
            sb.Append("Scheme: ").Append(vs.Scheme.FullIdent).Append(Environment.NewLine);
            if (var.Codelist != null)
                sb.Append("Codes: ").Append(var.Codelist.FullIdent).Append(Environment.NewLine);
            if (var.Qualitylist != null)
                sb.Append("Quality: ").Append(var.Qualitylist.FullIdent).Append(Environment.NewLine);
            sb.Append("*/").Append(Environment.NewLine);
        }

        /// <summary>
        /// Obtains a codelist merging codes and quality codes 
        /// (note: quality codes can exists even if no codelist associated to variable)
        /// </summary>
        /// <param name="var">the variable to operate on</param>
        /// <returns>codelist to use for SAS Format instructions</returns>
        private CodeListType GetFormatCodelist(Variable.Variable var)
        {
            CodeListType clt = null;
            if (var.Qualitylist != null)
                clt = var.Codelist != null ? var.GetCodelistAndQuality() : var.Qualitylist;
            else
                clt = var.Codelist;
            return clt;
        }

        private void FillCodelistFormat(StringBuilder sb, VariableSheet vs, Variable.Variable var)
        {
            string formatId = var.Concept.Id;
            // Get codelist with optionnal quality codes added
            CodeListType clt = GetFormatCodelist(var);
            // Ignore if no code defined
            if (clt != null && clt.CodeList.Count > 0)
            {
                CommentFormat(sb, vs, var);

                TextFormatType tft = var.FormatType;

                //If no format or undefined format, scan codes to check if integer
                if (tft == null || tft.TextType == TextTypeType.Undefined)
                    tft = clt.GetDefaultTextFormat();

                // Numeric or string codes
                bool isInteger = (tft.TextType == TextTypeType.Integer || tft.TextType == TextTypeType.Short || tft.TextType == TextTypeType.Long);
                // Value and codelist identification
                sb.Append("Value ");
                if (isInteger == false)
                    sb.Append('$');

                // Required to end format ID by an underscore
                sb.Append(formatId).Append('_').Append(Environment.NewLine);

                // Then in specified language a code = text
                foreach (ISdmxHierarchyListItem item in clt.CodeList)
                {
                    sb.Append(isInteger ? item.Id : QuoteStr(item.Id)).Append('=');
                    sb.Append(QuoteStr(item.Name.GetForLanguage(langCd))).Append(Environment.NewLine);
                }
                sb.Append(';').Append(Environment.NewLine);
            }
        }

        private string QuoteStr(string s)
        {
            return "\"" + s.Replace("\"", "'") + "\"";
        }
  
    }
}
